﻿//--------------------------------------------------------------
//
//作    者：蒙孝宗
//功能描述：数据库操作辅助类
//创建时间：2012-02-12
//修改记录：2012-02-22 改进事务处理方式
//         2012-04-11 修改读取配置文件的方法
//         2012-04-27 修改 GetProvider 方法,使其支持在同一个线程内可对不同数据库操作
//版    本：V1.3
//
//--------------------------------------------------------------

using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Reflection;
using System.Threading;
using System.Xml;

using DbHelper.Driver;

namespace DbHelper.Data
{
    /// <summary>
    /// 创建获取数据对象的实例
    /// </summary>
    public class MDbService
    {
        /// <summary>
        /// 缓存数据库驱动
        /// </summary>
        private static Dictionary<string, DbDriver> dictDriver = null;

        [ThreadStatic]
        private static Dictionary<string, IProvider> dictProvider = null;
        [ThreadStatic]
        private static IProvider curProvider = null;
        [ThreadStatic]
        private static string curDriverName = null;

        //记录注册的第一个ID
        internal static string FirstDriverName = null;


        /// <summary>
        /// 注册数据库驱动
        /// </summary>
        private static void RegisterDriver()
        {
            DbHelper.Config.Section section = ConfigurationManager.GetSection("drivers") as DbHelper.Config.Section;
            if (section == null)
            {
                throw new MDbException("请在配置文件里配置节点 <section name=\"drivers\" type=\"DbHelper.Config.Section,DbHelper\" /> .");
            }

            if (section.Drivers.Count == 0)
            {
                throw new MDbException(@"请在配置文件里配置数据库连接信息.");
            }

            dictDriver = new Dictionary<string, DbDriver>(4);

            foreach (DbHelper.Config.DriverElement driver in section.Drivers)
            {
                DbDriver dbDriver = new DbDriver();

                Assembly asm = Assembly.Load(driver.Assembly);
                dbDriver.DbConnection = (IDbConnection)asm.CreateInstance(driver.DBConnection.Type);
                dbDriver.DbCommand = dbDriver.DbConnection.CreateCommand();
                dbDriver.DbDataAdapter = (IDbDataAdapter)asm.CreateInstance(driver.DBDataAdapter.Type);
                dbDriver.DbDataAdapter.SelectCommand = dbDriver.DbCommand;

                if (!string.IsNullOrEmpty(driver.DBCommandBuilder.Type))
                {
                    object obj = asm.CreateInstance(driver.DBCommandBuilder.Type);
                    PropertyInfo[] pInfos = obj.GetType().GetProperties();
                    Type type = typeof(System.Data.IDbDataAdapter);
                    bool isOk = false;

                    foreach (PropertyInfo pInfo in pInfos)
                    {
                        Type[] types = pInfo.PropertyType.GetInterfaces();
                        foreach (Type t in types)
                        {
                            if (t == type)
                            {
                                pInfo.SetValue(obj, dbDriver.DbDataAdapter, null);
                                isOk = true;
                                break;
                            }
                        }

                        if (isOk) break;
                    }
                }

                //设置数据库连接
                if (!string.IsNullOrEmpty(driver.ConnectionString.Value))
                {
                    dbDriver.DbConnection.ConnectionString = driver.ConnectionString.Value;
                }

                dictDriver[driver.Name] = dbDriver;

                if (string.IsNullOrEmpty(FirstDriverName)) FirstDriverName = driver.Name;
            }
        }

        /// <summary>
        /// 注册数据库
        /// </summary>        
        public static void RegisterProvider()
        {
            lock (typeof(MDbService))
            {
                //不判断 null情况， if (dictDriver == null) 
                //目的是为了能够动态注册数据库服务
                RegisterDriver();
            }
        }

        /// <summary>
        /// 注册数据库
        /// </summary>        
        /// <param name="driverName">驱动器名称</param>
        /// <param name="connString">数据库连接字符串</param>
        public static void RegisterProvider(string driverName, string connString)
        {
            lock (typeof(MDbService))
            {
                if (dictDriver == null) RegisterDriver();
                dictDriver[driverName].DbConnection.ConnectionString = connString;
            }
        }

        /// <summary>
        /// 获取数据库服务实例
        /// <para>注意：不应该缓存，应该每次都读取。原因是不同的线程会得到不同的对象，在同一个线程内只会返回同一个对象</para>
        /// </summary>
        /// <param name="driverName"></param>
        /// <returns></returns>
        public static IProvider GetProvider(string driverName)
        {
            if (curDriverName != driverName)
            {
                curDriverName = driverName;

                if (dictProvider == null) dictProvider = new Dictionary<string, IProvider>();

                if (!dictProvider.TryGetValue(driverName, out curProvider))
                {
                    curProvider = CreateProvider(dictDriver[driverName]);
                    dictProvider.Add(driverName, curProvider);
                }
            }

            return curProvider;
        }

        /// <summary>
        /// 获取注册的第一个数据库服务实例
        /// <para>注意：不应该缓存，应该每次都读取。原因是不同的线程会得到不同的对象，在同一个线程内只会返回同一个对象</para>
        /// </summary>
        /// <returns></returns>
        public static IProvider GetProvider()
        {
            return GetProvider(FirstDriverName);
        }

        /// <summary>
        /// 创建数据库服务实例
        /// </summary>
        /// <param name="dbDriver"></param>
        /// <param name="connString"></param>
        /// <returns></returns>
        private static IProvider CreateProvider(DbDriver dbDriver)
        {
            return new DbProvider(dbDriver);
        }
    }
}
